/*
 * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

/*
 * scalbn (double x, int n)
 * scalbn(x,n) returns x* 2**n  computed by  exponent
 * manipulation rather than by actually performing an
 * exponentiation or a multiplication.
 */

namespace IKVM.Runtime.Util.Java.Lang
{
    static partial class fdlibm
    {
        static double scalbn(double x, int n)
        {
            const double
    two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */
    twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */
    huge = 1.0e+300,
    tiny = 1.0e-300;

            int k, hx, lx;
            hx = __HI(x);
            lx = __LO(x);
            k = (hx & 0x7ff00000) >> 20;                /* extract exponent */
            if (k == 0)
            {                             /* 0 or subnormal x */
                if ((lx | (hx & 0x7fffffff)) == 0) return x; /* +-0 */
                x *= two54;
                hx = __HI(x);
                k = ((hx & 0x7ff00000) >> 20) - 54;
                if (n < -50000) return tiny * x;       /*underflow*/
            }
            if (k == 0x7ff) return x + x;               /* NaN or Inf */
            k = k + n;
            if (k > 0x7fe) return huge * copysign(huge, x); /* overflow  */
            if (k > 0)                              /* normal result */
            { x = __HI(x, (hx & unchecked((int)0x800fffff)) | (k << 20)); return x; }
            if (k <= -54)
            {
                if (n > 50000)      /* in case integer overflow in n+k */
                    return huge * copysign(huge, x);   /*overflow*/
                else return tiny * copysign(tiny, x);  /*underflow*/
            }
            k += 54;                                /* subnormal result */
            x = __HI(x, (hx & unchecked((int)0x800fffff)) | (k << 20));
            return x * twom54;
        }
    }
}